﻿using OpenCvSharp;
using System;
using System.Drawing;
using System.Windows.Forms;

namespace OpenCVtest1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Mat src = Cv2.ImRead("lenna.png", ImreadModes.GrayScale);
            //Mat dst = new Mat();

            //Cv2.Canny(src, dst, 50, 200);
            //using (new Window("src image", src))
            //using (new Window("dst image", dst))
            //{
            //    Cv2.WaitKey();
            //}
            //string result = MatchHist();
            //MessageBox.Show(result);
            if (CmbBoxSizeMode.Items.Count > 1)
            {
                CmbBoxSizeMode.SelectedIndex = 1;
            }
        }

        public void Set_sizeMode()
        {
            if (this.CmbBoxSizeMode.Items.Count < 2)
            {
                return;
            }
            if (CmbBoxSizeMode.SelectedIndex == 0)
            {
                this.PictureBox1.SizeMode = PictureBoxSizeMode.Normal;
                this.PictureBox2.SizeMode = PictureBoxSizeMode.Normal;
            }

            if (CmbBoxSizeMode.SelectedIndex == 1)
            {
                this.PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
                this.PictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
            }

            if (CmbBoxSizeMode.SelectedIndex == 2)
            {
                this.PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
                this.PictureBox2.SizeMode = PictureBoxSizeMode.AutoSize;
            }

            if (CmbBoxSizeMode.SelectedIndex == 3)
            {
                this.PictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
                this.PictureBox2.SizeMode = PictureBoxSizeMode.CenterImage;
            }

            if (CmbBoxSizeMode.SelectedIndex == 4)
            {
                this.PictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
                this.PictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
            }
        }

        //原理就是把两个图片转化为大小相同的灰度图，然后相减，再和原图比较一下
        //算法有不足，但是基本满足需求，希望能抛砖引玉
        //成对几何直方图匹配 
        float Similar(ref Mat src, ref Mat src2)
        {
            Mat gray1 = new Mat(src.Size(), src.Type()),
                gray2 = new Mat(src2.Size(), src2.Type());
            Cv2.CvtColor(src, gray1, ColorConversionCodes.BGR2GRAY);
            Cv2.CvtColor(src2, gray2, ColorConversionCodes.BGR2GRAY);

            var size = new OpenCvSharp.Size(512, 512);
            using (var scaledImg1 = gray1.Resize(size))
            using (var scaledImg2 = gray2.Resize(size))
            {
                Cv2.Threshold(scaledImg1, scaledImg1, 128, 255, ThresholdTypes.BinaryInv);
                Cv2.Threshold(scaledImg2, scaledImg2, 128, 255, ThresholdTypes.BinaryInv);
                Mat res = new Mat(size, scaledImg1.Type());
                Cv2.Absdiff(scaledImg1, scaledImg2, res);
                //Cv2.ImShow("aa", scaledImg1);
                var all = (float)scaledImg1.Sum();
                var result = (float)res.Sum();
                //print("result:" + (1 - result / all));
                return (1 - result / all);
            }
        }


        //  平均哈希算法 OpenCV
        //如果不相同的数据位数不超过5，就说明两张图像很相似；如果大于10，就说明这是两张不同的图像。
        bool A_Hxsf(ref Mat graySrc1, ref Mat graySrc2)
        {
            //OpenCvSharp.Size size = new OpenCvSharp.Size(8, 8);
            Mat matDst1 = new Mat(); Mat matDst2 = new Mat();
            Cv2.Resize(graySrc1, matDst1, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);
            Cv2.Resize(graySrc2, matDst2, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);

            int iAvg1 = 0, iAvg2 = 0;
            int[] arr1 = new int[64]; int[] arr2 = new int[64];

            for (int row = 0; row < 8; row++)
            {
                int tmp = row * 8;
                for (int col = 0; col < 8; col++)
                {
                    byte p1 = matDst1.At<byte>(row, col); //获对应矩阵坐标的取像素
                    byte p2 = matDst2.At<byte>(row, col); //获对应矩阵坐标的取像素
                                                          //byte value = byte.Parse((255 - p).ToString()); //反转像素值
                                                          //dst.Set(row, col, value); //赋值
                    int tmp1 = tmp + col;
                    arr1[tmp1] = p1 / 4 * 4;
                    arr2[tmp1] = p2 / 4 * 4;

                    iAvg1 += arr1[tmp1];
                    iAvg2 += arr2[tmp1];
                }
            }

            iAvg1 /= 64;
            iAvg2 /= 64;

            for (int i = 0; i < 64; i++)
            {
                arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
                arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
            }

            int iDiffNum = 0;

            for (int i = 0; i < 64; i++)
                if (arr1[i] != arr2[i])
                    ++iDiffNum;

            //cout << "iDiffNum = " << iDiffNum << endl;

            if (iDiffNum <= 5)
            {
                return true;
                //cout << "two images are very similar!" << endl;
            }
            else if (iDiffNum > 10)
            {
                return false; //cout << "they are two different images!" << endl;
            }
            else
            {
                return false;
                //cout << "two image are somewhat similar!" << endl;
            }

        }


        // 感知哈希算法 OpenCV
        //如果不相同的数据位数不超过5，就说明两张图像很相似；如果大于10，就说明这是两张不同的图像。
        bool P_Hxsf(ref Mat graySrc1, ref Mat graySrc2)
        {
            //OpenCvSharp.Size size = new OpenCvSharp.Size(8, 8);
            Mat matDst1 = new Mat(); Mat matDst2 = new Mat();
            Cv2.Resize(graySrc1, matDst1, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Cubic);
            Cv2.Resize(graySrc2, matDst2, new OpenCvSharp.Size(32, 32), 0, 0, InterpolationFlags.Cubic);

            matDst1.ConvertTo(matDst1, MatType.CV_32F);
            matDst2.ConvertTo(matDst2, MatType.CV_32F);

            matDst1 = matDst1.Dct();
            matDst2 = matDst2.Dct();

            int iAvg1 = 0, iAvg2 = 0;
            int[] arr1 = new int[64]; int[] arr2 = new int[64];

            for (int row = 0; row < 8; row++)
            {
                int tmp = row * 8;
                for (int col = 0; col < 8; col++)
                {
                    byte p1 = matDst1.At<byte>(row, col); //获对应矩阵坐标的取像素
                    byte p2 = matDst2.At<byte>(row, col); //获对应矩阵坐标的取像素
                                                          //byte value = byte.Parse((255 - p).ToString()); //反转像素值
                                                          //dst.Set(row, col, value); //赋值
                    int tmp1 = tmp + col;
                    arr1[tmp1] = p1 / 4 * 4;
                    arr2[tmp1] = p2 / 4 * 4;

                    iAvg1 += arr1[tmp1];
                    iAvg2 += arr2[tmp1];
                }
            }

            iAvg1 /= 64;
            iAvg2 /= 64;

            for (int i = 0; i < 64; i++)
            {
                arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
                arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
            }

            int iDiffNum = 0;

            for (int i = 0; i < 64; i++)
                if (arr1[i] != arr2[i])
                    ++iDiffNum;

            //cout << "iDiffNum = " << iDiffNum << endl;

            if (iDiffNum <= 5)
            {
                return true;
                //cout << "two images are very similar!" << endl;
            }
            else if (iDiffNum > 10)
            {
                return false; //cout << "they are two different images!" << endl;
            }
            else
            {
                return false;
                //cout << "two image are somewhat similar!" << endl;
            }

        }



        private void CmbBoxSizeMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            Set_sizeMode();
        }

        private void BtnOpenFile1_Click(object sender, EventArgs e)
        {
            OpenFileDialog1.Title = "C# Corner Open File Dialog";
            OpenFileDialog1.InitialDirectory = @"r:\";
            //openFileDialog1.Filter = "All files（*.*）|*.*|bmp files(*.bmp)|*.bmp";
            /*
             * FilterIndex 属性用于选择了何种文件类型,缺省设置为0,系统取Filter属性设置第一项
             * ,相当于FilterIndex 属性设置为1.如果你编了3个文件类型，当FilterIndex ＝2时是指第2个.
             */
            OpenFileDialog1.FilterIndex = 2;
            /*
             *如果值为false，那么下一次选择文件的初始目录是上一次你选择的那个目录，
             *不固定；如果值为true，每次打开这个对话框初始目录不随你的选择而改变，是固定的  
             */
            OpenFileDialog1.RestoreDirectory = true;
            if (OpenFileDialog1.ShowDialog() == DialogResult.OK)
            {
                //textBox1.Text = System.IO.Path.GetFileNameWithoutExtension(openFileDialog1.FileName);
                this.tbFile1.Text = System.IO.Path.GetFullPath(OpenFileDialog1.FileName); //绝对路径
                this.PictureBox1.Load(this.tbFile1.Text);
                //System.IO.Path.GetExtension(openFileDialog1.FileName); //文件扩展名
                //System.IO.Path.GetFileNameWithoutExtension(openFileDialog1.FileName); //文件名没有扩展名
                //System.IO.Path.GetFileName(openFileDialog1.FileName); //得到文件
                //System.IO.Path.GetDirectoryName(openFileDialog1.FileName); //得到路径
            }
        }

        private void BtnOpenFile2_Click(object sender, EventArgs e)
        {
            OpenFileDialog1.Title = "C# Corner Open File Dialog";
            OpenFileDialog1.InitialDirectory = @"r:\";
            //openFileDialog1.Filter = "All files（*.*）|*.*|All files(*.*)|*.* ";
            /*
             * FilterIndex 属性用于选择了何种文件类型,缺省设置为0,系统取Filter属性设置第一项
             * ,相当于FilterIndex 属性设置为1.如果你编了3个文件类型，当FilterIndex ＝2时是指第2个.
             */
            OpenFileDialog1.FilterIndex = 2;
            /*
             *如果值为false，那么下一次选择文件的初始目录是上一次你选择的那个目录，
             *不固定；如果值为true，每次打开这个对话框初始目录不随你的选择而改变，是固定的  
             */
            OpenFileDialog1.RestoreDirectory = true;
            if (OpenFileDialog1.ShowDialog() == DialogResult.OK)
            {
                //textBox1.Text = System.IO.Path.GetFileNameWithoutExtension(openFileDialog1.FileName);
                tbFile2.Text = System.IO.Path.GetFullPath(OpenFileDialog1.FileName); //绝对路径
                this.PictureBox2.Load(this.tbFile2.Text);
                //System.IO.Path.GetExtension(openFileDialog1.FileName); //文件扩展名
                //System.IO.Path.GetFileNameWithoutExtension(openFileDialog1.FileName); //文件名没有扩展名
                //System.IO.Path.GetFileName(openFileDialog1.FileName); //得到文件
                //System.IO.Path.GetDirectoryName(openFileDialog1.FileName); //得到路径
            }
        }
        private void BtnTxdb_aHash_Click(object sender, EventArgs e)
        {
            this.tbResult.Text = "  \r\n";
            Mat matKongBai = new Mat(this.tbFile1.Text, ImreadModes.Grayscale);

            //string strFileName2 = string.Format(  "r:\\k{0}.bmp", i);
            Mat matCeShi = new Mat(this.tbFile2.Text, ImreadModes.Grayscale);

            //Mat matDst1 = new Mat(); Mat matDst2 = new Mat();
            //Cv2.Resize(src, matDst1, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);
            //Cv2.Resize(src2, matDst2, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);

            //using (new Window("src image", matDst1))
            //using (new Window("dst image", matDst2))
            //{
            //    Cv2.WaitKey();
            //}

            //cv::resize(matSrc2, matDst2, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);
            //update 20181206 for the bug cvtColor

            //Mat temp1 = matDst1;
            //Mat temp2 = matDst2;

            //Cv2.CvtColor(temp1, matDst1, ColorConversionCodes.BGR2GRAY);
            //Cv2.CvtColor(temp2, matDst2, ColorConversionCodes.BGR2GRAY);

            bool bool_isKongBai = A_Hxsf(ref matKongBai, ref matCeShi);

            this.tbResult.Text = this.tbResult.Text + this.tbFile1.Text + "\r\n" + this.tbFile2.Text + " \r\nGzHxsf = " + bool_isKongBai.ToString() + "\r\n\r\n";

            //using (new Window("src image", matKongBai))
            //using (new Window("dst image", matCeShi))
            //{
            //    Cv2.WaitKey();
            //}

            //float float_Similar1 = Similar(ref src, ref src2);
        }

        private void BrnDuiBi_GZHXSF_Click(object sender, EventArgs e)
        {
            this.tbResult.Text = "  \r\n";
            Mat matKongBai = new Mat(this.tbFile1.Text, ImreadModes.Grayscale);

            //string strFileName2 = string.Format(  "r:\\k{0}.bmp", i);
            Mat matCeShi = new Mat(this.tbFile2.Text, ImreadModes.Grayscale);

            //Mat matDst1 = new Mat(); Mat matDst2 = new Mat();
            //Cv2.Resize(src, matDst1, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);
            //Cv2.Resize(src2, matDst2, new OpenCvSharp.Size(8, 8), 0, 0, InterpolationFlags.Cubic);

            //using (new Window("src image", matDst1))
            //using (new Window("dst image", matDst2))
            //{
            //    Cv2.WaitKey();
            //}

            //cv::resize(matSrc2, matDst2, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);
            //update 20181206 for the bug cvtColor

            //Mat temp1 = matDst1;
            //Mat temp2 = matDst2;

            //Cv2.CvtColor(temp1, matDst1, ColorConversionCodes.BGR2GRAY);
            //Cv2.CvtColor(temp2, matDst2, ColorConversionCodes.BGR2GRAY);

            bool bool_isKongBai = P_Hxsf(ref matKongBai, ref matCeShi);

            this.tbResult.Text = this.tbResult.Text + this.tbFile1.Text + "\r\n" + this.tbFile2.Text + " \r\nGzHxsf = " + bool_isKongBai.ToString() + "\r\n\r\n";

            //using (new Window("src image", matKongBai))
            //using (new Window("dst image", matCeShi))
            //{
            //    Cv2.WaitKey();
            //}

            //float float_Similar1 = Similar(ref src, ref src2);
        }

        private void BtnDbOpencv_Click(object sender, EventArgs e)
        {
            this.tbResult.Text = this.tbFile1.Text + "\r\n\r\n";
            Mat src = new Mat(this.tbFile1.Text, ImreadModes.Color);


            //string strFileName2 = string.Format(  "r:\\k{0}.bmp", i);
            Mat src2 = new Mat(this.tbFile2.Text, ImreadModes.Color);

            float float_Similar1 = Similar(ref src, ref src2);

            this.tbResult.Text = this.tbResult.Text + this.tbFile2.Text + " \r\n = " + float_Similar1.ToString() + "\r\n\r\n";

        }

        private void BtnDuiBi2_Click(object sender, EventArgs e)
        {
            int countSame = 0;
            int countDifferent = 0;
            Bitmap bitmapKongBai = new Bitmap(this.tbFile1.Text);
            Bitmap bitmapTarget = new Bitmap(this.tbFile2.Text);
            //照片尺寸必须一样
            for (int i = 0; i < bitmapTarget.Width; i++)
            {
                for (int j = 0; j < bitmapTarget.Height; j++)
                {
                    if (bitmapKongBai.GetPixel(i, j).Equals(bitmapTarget.GetPixel(i, j)))
                    {
                        countSame++;
                        if (countSame > 500)
                        {
                            //stopwatch.Stop();
                            //Console.WriteLine("相同像素个数：" + countSame + "，不同像素个数：" + countDifferent + "用时：" + stopwatch.ElapsedMilliseconds + " 毫秒");
                            //lstPoint0.Add(pItem0);
                            break;

                        }
                    }
                    else
                    {
                        countDifferent++;
                    }
                    if (countSame > 500)
                    {
                        //stopwatch.Stop();
                        //Console.WriteLine("相同像素个数：" + countSame + "，不同像素个数：" + countDifferent + "用时：" + stopwatch.ElapsedMilliseconds + " 毫秒");                         
                        this.tbResult.Text = this.tbFile1.Text + "\r\n" + this.tbFile2.Text + "\r\n相同";
                        break;
                    }
                }
            }
            this.tbResult.Text = this.tbFile1.Text + "\r\n" + this.tbFile2.Text + "\r\n" + "相同像素个数：" + countSame + "，不同像素个数：" + countDifferent;

        }

        private void BtnTest1_Click(object sender, EventArgs e)
        {
            //Mat matAllScreen = new Mat(@"r:\zAll.bmp", ImreadModes.Grayscale);

            //imageROI = matAllScreen.AdjustROI( (Rect(500, 250, logo.cols, logo.rows));

            //Rect roi = new Rect(400, 300, 300, 350);//首先要用个rect确定我们的兴趣区域在哪
            //Mat ImageROI;//ImageROI = new Mat(matAllScreen, roi);//新建一个mat，把roi内的图像加载到里面去。

            //using (new Window("dst image", ImageROI))
            //{
            //    Cv2.WaitKey();
            //}


        }

        private void BtnJiSuan_Click(object sender, EventArgs e)
        {
            this.tbResult.Text = this.tbFile1.Text + "\r\n\r\n";
            Mat src = new Mat(this.tbFile1.Text, ImreadModes.Color);

            for (int i = 0; i < 140; i++)
            {
                string strFileName2 = string.Format("r:\\k{0}.bmp", i);
                Mat src2 = new Mat(strFileName2, ImreadModes.Color);

                float float_Similar1 = Similar(ref src, ref src2);

                if (float_Similar1 > 0.9)
                {
                    this.tbResult.Text = this.tbResult.Text + strFileName2 + float_Similar1.ToString() + "\r\n\r\n";
                }


            }
        }


    }
}
